package customer

import (
	"context"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/google/wire"
	"reflect"
	"sieve_admin_server_userpass/app/dao"
	"sieve_admin_server_userpass/app/dao/daily_recharge"
	"sieve_admin_server_userpass/app/schema"
	schemaCustomer "sieve_admin_server_userpass/app/schema/customer"
	serviceSys "sieve_admin_server_userpass/app/service/sys"
	serviceUtil "sieve_admin_server_userpass/app/service/util"
	"sieve_admin_server_userpass/lib/util/convert"
	pkgUtil "sieve_admin_server_userpass/pkg/util"
	"strings"
	"time"
)

var (
	DailyRechargeSet = wire.NewSet(wire.Struct(new(DailyRechargeSrv), "*"))
)

type DailyRechargeSrv struct {
	UserSrv           *UserSrv
	RoleSrv           *serviceSys.RoleSrv
	DailyRechargeRepo *dao.DailyRechargeRepo
}

func (a *DailyRechargeSrv) Create(ctx context.Context, item map[string]interface{}) interface{} {

	var (
		now = time.Now().Unix()
		def = map[string]interface{}{
			"create_at":  now,
			"updated_at": now,
		}
	)

	for k, v := range def {
		item[k] = v
	}

	return a.DailyRechargeRepo.Create(ctx, item)
}

func (a *DailyRechargeSrv) addQueryResponseSeq(p schema.PaginationParam, req interface{}) interface{} {

	if req != nil {

		var enable bool
		if _, ok := req.(map[string]interface{})["total"]; ok {
			if _, ok := req.(map[string]interface{})["list"]; ok {
				enable = true
			}
		}
		if enable {
			var (
				indexStart = 1
				total      = req.(map[string]interface{})["total"].(uint64)
			)

			for i, _ := range req.(map[string]interface{})["list"].([]interface{}) {

				// resp := v.(*schemaCustomer.RechargeQueryRsp)
				seqNo := int(total) - (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + indexStart
				// seqNo := (p.PageSize*(p.PageIndex-1) + (int(i) + 1)) + autoIndexStart
				// req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.UserQueryRsp).Seq = int64(seqNo)
				req.(map[string]interface{})["list"].([]interface{})[i].(*schemaCustomer.DailyRechargeQueryResp).SeqNo = int64(seqNo)
			}
		}
	}

	return req
}

func (a *DailyRechargeSrv) Query(ctx context.Context, uid uint64, reqArgs map[string]interface{}, p schema.PaginationParam) interface{} {

	var cusSQL string
	if _, ok := reqArgs["date"]; ok {
		queryDates := strings.Split(reqArgs["date"].(string), ",")

		if len(queryDates) == 2 {
			cusSQL = fmt.Sprintf("date >= '%v' AND date <= '%v'", queryDates[0], queryDates[1])
			ctx = context.WithValue(ctx,
				"condition_customized", cusSQL,
			)
			delete(reqArgs, "date")
		}
	}

	var (
		entity  = daily_recharge.DailyRechargeStatistics{}
		repKeys = []string{
			fmt.Sprintf("%v.id as id", entity.TableName()),
			"date as date",
			"SUM(recharge_points_total) as recharge_points_total",
			"SUM(bonus_points_total) as bonus_points_total",
			"daily_recharge_statistics.leader_id as leader_id",
			"leader_name as leader_name",
		}
	)

	ctx = context.WithValue(
		context.WithValue(ctx, "column_types", schemaCustomer.DailyRechargeQueryResp{}),
		"group_by", "date,leader_id",
	)

	roleId, err := a.UserSrv.GetRoleID(ctx, uid)
	if err != nil {
		return err
	}

	if a.RoleSrv.IsAdminRoleId(roleId) {
		// 不管是不是 首页查询sql都是一样的了
		// if v, ok := reqArgs["overview"]; ok {
		// if v.(uint64) == 1 {
		/*
			管理端的今日充值统计和只需要统计管理员+业务员对代理商的充值积分。然后业务员看自己今天对代理商的充值积分。管理员看整个管理端（所有业务员+所有管理员）对代理商的充值积分。
		*/

		// var (
		//	joinString = fmt.Sprintf(
		//		"INNER JOIN user ON daily_recharge_statistics.leader_id = user.id AND user.role_id IN (%v,%v) AND user.deleted = 0", roleId, a.RoleSrv.GetSalespersonRole().ID)
		// )

		var (
			joinString = fmt.Sprintf(`INNER JOIN user ON daily_recharge_statistics.leader_id = user.id AND user.role_id IN (%v ,%v)`,
				roleId,
				a.RoleSrv.GetSalespersonRole().ID)
		)

		ctx = context.WithValue(ctx, "join", joinString)
		// }
		delete(reqArgs, "overview")
		// }
	}

	if a.RoleSrv.IsSalespersonRole(roleId) {
		reqArgs["leader_id"] = uid
	}
	delete(reqArgs, "overview")
	req, err := a.DailyRechargeRepo.Query(ctx, reqArgs, p, repKeys)
	if err != nil {
		return err
	}

	if req != nil {

		var (
			rpt uint64
			bpt uint64
		)
		for _, v := range req.(map[string]interface{})["list"].([]interface{}) {

			respDRs := v.(*schemaCustomer.DailyRechargeQueryResp)
			rpt += respDRs.RechargePointsTotal
			bpt += respDRs.BonusPointsTotal
		}

		req.(map[string]interface{})["all"] = map[string]interface{}{
			"rpt": rpt,
			"bpt": bpt,
		}
	}
	return a.addQueryResponseSeq(p, req)
}

func (a *DailyRechargeSrv) Export(ctx context.Context, uid uint64, item map[string]interface{}, fCallBack func(fileName string)) interface{} {

	var (
		p = schema.PaginationParam{
			OnlyData: true,
		}
		queryArgs = map[string]interface{}{
			"id": func() string {
				ids := item["ids"].(string)
				return fmt.Sprintf("(%v)", strings.Join(strings.Split(ids, "|"), ","))
			}(),
		}
		seqs = make(map[string]string)
	)

	for i, v := range strings.Split(item["ids"].(string), "|") {
		seqs[v] = strings.Split(item["seqs"].(string), "|")[i]
	}

	delete(queryArgs, "id")
	// ctx = context.WithValue(ctx,
	//	"condition", map[string]string{"id": "IN"},
	// )

	req := a.Query(ctx, uid, queryArgs, p)
	if req != nil {
		if err, ok := req.(error); ok {
			return err
		}
	}

	var (
		reqCopy   = map[string]interface{}{}
		v         = req.(map[string]interface{})
		listValue []interface{}
	)

	for key, value := range req.(map[string]interface{}) {
		if key == "list" {
			continue
		}
		reqCopy[key] = value
	}

	for _, vv := range v["list"].([]interface{}) {
		itemData := vv.(*schemaCustomer.DailyRechargeQueryResp)
		if _, ok := seqs[fmt.Sprintf("%v", itemData.ID)]; !ok {
			continue
		}
		listValue = append(listValue, vv)
	}

	reqCopy["list"] = listValue
	req = reqCopy

	selectedItems := []string{
		"id",
		"date",
		"recharge_points_total",
		"bonus_points_total",
	}
	req = a.export(ctx, req, 1, seqs, strings.Join(selectedItems, "|"))
	if req != nil {
		if _, ok := req.(error); ok {
			return req
		}
	}

	fCallBack(req.(string))

	return req
}

func (a *DailyRechargeSrv) export(ctx context.Context, req interface{}, funcTy int, seqs map[string]string, selectedItems string) interface{} {

	var (
		xlsx       = excelize.NewFile()
		categories = map[string]string{
			"A1": "序号",
			"B1": "充值日期",
			"C1": "充值总额",
			"D1": "赠送积分总额",
		}
		selectedItemMap = make(map[string]int)
		colWidths       = map[string]float64{"A": 8, "B": 22, "C": 18, "D": 12}
	)

	for key, value := range categories {
		xlsx.SetCellValue("Sheet1", key, value)
		_style, err := xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#EEECE1"],"pattern":1},"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"family":"宋体","size":10}}`)
		if err == nil {
			xlsx.SetCellStyle("Sheet1", key, key, _style)
		}
	}

	xlsx.SetRowHeight("Sheet1", 1, 20)

	for k, v := range colWidths {
		xlsx.SetColWidth("Sheet1", k, k, v)
	}

	for i, v := range strings.Split(fmt.Sprintf("%v", selectedItems), "|") {
		selectedItemMap[v] = i
	}

	p := map[string]struct{}{
		"recharge_points_total": {},
		"bonus_points_total":    {},
	}

	v := req.(map[string]interface{})
	for index, vv := range v["list"].([]interface{}) {

		var (
			columIndex  = 'A'
			columOffset = 1
		)

		for kkk, vvv := range pkgUtil.Struct2Map(vv, "json") {

			if len(selectedItemMap) > 0 {
				if i, ok := selectedItemMap[kkk]; !ok {
					continue
				} else {
					columOffset = i
				}
			}

			cell := fmt.Sprintf("%c", int(columIndex)+columOffset) + convert.ToString(index+2)

			if reflect.TypeOf(vvv).Kind() == reflect.Ptr {
				vOf := reflect.ValueOf(vvv)
				if vOf.IsNil() {
					vvv = ""
				} else {
					vvv = vOf.Elem()
				}
			}

			if kkk == "id" {
				vvv = seqs[fmt.Sprintf("%v", vvv.(uint64))]
			}

			if _, ok := p[kkk]; ok {
				vvv = pkgUtil.Decimal(float64(vvv.(uint64))/10000.0, 5)
			}

			xlsx.SetCellValue("Sheet1", cell, vvv)
		}

		xlsx.SetRowHeight("Sheet1", index+2, 18)
	}

	xlsx.SetSheetName("Sheet1", "第一页")

	filPath, fileName := a.getExportPath(convert.ToString(time.Now().UnixMilli())+".csv", 1)
	err := xlsx.SaveAs(filPath)
	if err != nil {
		return nil
	}

	req = fileName

	return req
}

func (a *DailyRechargeSrv) getExportPath(fileName string, bizTy int) (string, string) {

	var (
		bizTyMap = map[int]string{
			1: "daily_recharge_statistics",
		}
	)

	relativePath := fmt.Sprintf("%v/export/%v", bizTyMap[bizTy], fileName)

	return serviceUtil.GetFilePath(
		fmt.Sprintf("%v/%v",
			serviceUtil.FileStorage(),
			relativePath),
	), relativePath
}
